import { Popper } from '@mui/material';
import {
  ChangeEvent,
  forwardRef,
  isValidElement,
  ReactNode,
  useEffect,
  useRef,
  useState,
} from 'react';
import { mergeRefs } from 'react-merge-refs';
import SelectContext from 'src/context/SelectContext';
import style from './AutoComplete.module.scss';
import Input, { Props as InputProps } from '../Input';

/**
 * usage example:
 *
 * <AutoComplete>
 *   <AutoCompleteOption value="aa">a</AutoCompleteOption>
 *   <AutoCompleteOption value="bb">b</AutoCompleteOption>
 * </AutoComplete>
 */

export type Props = Omit<InputProps, 'onChange'> & {
  children: ReactNode | ReactNode[];
  onChange?: (v: string) => void;
  filter?: boolean;
};

const AutoComplete = forwardRef<HTMLInputElement, Props>(
  ({ children, hint, error, disabled, onChange, onBlur, regex, filter = true, ...props }, ref) => {
    const [open, setOpen] = useState<boolean>(false);
    const [options, setOptions] = useState<{ value: string; children: ReactNode }[]>([]);
    const [value, setValue] = useState<string>();
    const inputRef = useRef<HTMLInputElement>(null);

    useEffect(() => {
      setOptions(
        (Array.isArray(children) ? children : [children]).map((child) =>
          isValidElement(child) ? child.props : null,
        ),
      );
    }, [children]);

    const handleChange = (v: string) => {
      setOpen(false);
      setValue(v);
      onChange && onChange(v);
    };

    const onInput = (v: ChangeEvent<HTMLInputElement>) => {
      if (regex !== undefined && regex.test(v.target.value) === false) return;
      setValue(v.target.value);
      onChange && onChange(v.target.value);
    };

    return (
      <SelectContext.Provider value={{ current: value ?? '', handleChange, filter }}>
        <div>
          <Input
            disabled={disabled}
            ref={mergeRefs([inputRef, ref])}
            onClick={() => setOpen(true)}
            onBlur={() => {
              // onBlur && onBlur;
              setOpen(false);
            }}
            onChange={onInput}
            value={value}
            {...props}
          />
          {typeof error === 'string' && <div className={style.errorMessage}>{error}</div>}
          {hint && <div className={style.hint}>{hint}</div>}
        </div>
        <Popper
          open={
            open &&
            (!filter ||
              options.filter((v) =>
                v.value.toLowerCase().includes(value?.toLocaleLowerCase() ?? ''),
              ).length > 0)
          }
          anchorEl={inputRef.current}
          style={{ width: inputRef.current?.offsetWidth }}
          className={style.popper}
        >
          {children}
        </Popper>
      </SelectContext.Provider>
    );
  },
);

AutoComplete.displayName = 'AutoComplete';

export default AutoComplete;
